package com.work.test;

import java.util.*;

import org.hibernate.*;

import com.work.db.HibernateUtil;

public abstract class AbstractDao<T> {

	private Class<T> persistentClass;
	protected String persistentClassString;
	
	private final static String fromStr = "from ";

	public AbstractDao(Class<T> aClass){
		this.persistentClass = aClass;
		this.persistentClassString = aClass.getCanonicalName();
	}
	
	public T save(T entity) {
		Session session = openSession();
		session.saveOrUpdate(entity);
		closeSession(session);
		return entity;
	}
	
	/**
	 * Uwaga przy użyciu - usuwa na stałe
	 * @param entity
	 * @return
	 */
	public T delete(T entity) {
		Session session = openSession();
		session.delete(entity);
		closeSession(session);
		return entity;
	}
	
	@SuppressWarnings("unchecked")
	public List<T> findAll() {
		Session session = openSession();
		List<T> list = session.createQuery(fromStr + persistentClassString).list();
		list = touchList(list);
		closeSession(session);
		return list;
	}
	
	@SuppressWarnings("unchecked")
	public List<T> findMultiFromQuery_where(String where) {
		String query = fromStr + persistentClassString + " " + where;
		try {
			Session session = openSession();			
			List<T> list  = session.createQuery(query).list();
			list = touchList(list);
			closeSession(session);
			return list; 
		} catch (NonUniqueResultException ex) {
			return null;
		}
	}
	

	@SuppressWarnings("unchecked")
	public T find(long id) {
		Session session = openSession();
		T entity = (T)session.get(persistentClass, id);
		entity = touch(entity);
		closeSession(session);
		return entity;
	}
	
	@SuppressWarnings("unchecked")
	public T findSingleFromQuery_where(String where) {
		String query = fromStr + persistentClassString + " " + where;
		try {
			Session session = openSession();			
			T single = (T)session.createQuery(query).uniqueResult();
			single = touch(single);
			closeSession(session);
			return single; 
		} catch (NonUniqueResultException ex) {
			return null;
		}
	}
	
	@SuppressWarnings("unchecked")
	public T findSingleFromQuery(String hql) {
		try {
			Session session = openSession();			
			T single = (T)session.createQuery(hql).uniqueResult();
			single = touch(single);
			closeSession(session);
			return single; 
		} catch (NonUniqueResultException ex) {
			return null;
		}
	}
	
	public Integer findIntegerFromQuery(String hql) {
		try {
			Session session = openSession();			
			Integer i = (Integer)session.createQuery(hql).uniqueResult();
			closeSession(session);
			return i; 
		} catch (NonUniqueResultException ex) {
			return null;
		}
	}
	
	protected Session openSession() {
		Session session = HibernateUtil.getSessionFactory().openSession();
		session.beginTransaction();
		return session;
	}
	
	/**
	 * Commituje transakcję i zamyka sesję hibernate
	 * @param session
	 */
	protected void closeSession(Session session) {
		session.getTransaction().commit();
		session.close();
	}
	
	protected abstract T touch(T entity);
	
	protected List<T> touchList(List<T> list) {
		List<T> touchedList = new ArrayList<T>();
		for (T entity : list) {
			entity = touch(entity);
			touchedList.add(entity);
		}
		return touchedList;
	}
}
